import { z } from 'zod';
import zodToJsonSchema from 'zod-to-json-schema';

import { HelperTools } from '../const.js';
import { fetchApifyDocsCache } from '../state.js';
import type { InternalToolArgs, ToolEntry, ToolInputSchema } from '../types.js';
import { ajv } from '../utils/ajv.js';
import { htmlToMarkdown } from '../utils/html-to-md.js';
import { logHttpError } from '../utils/logging.js';
import { buildMCPResponse } from '../utils/mcp.js';

const fetchApifyDocsToolArgsSchema = z.object({
    url: z.string()
        .min(1)
        .describe(`URL of the Apify documentation page to fetch. This should be the full URL, including the protocol (e.g., https://docs.apify.com/).`),
});

export const fetchApifyDocsTool: ToolEntry = {
    type: 'internal',
    name: HelperTools.DOCS_FETCH,
    description: `Fetch the full content of an Apify documentation page by its URL.
Use this after finding a relevant page with the ${HelperTools.DOCS_SEARCH} tool.

USAGE:
- Use when you need the complete content of a specific docs page for detailed answers.

USAGE EXAMPLES:
- user_input: Fetch https://docs.apify.com/platform/actors/running#builds
- user_input: Fetch https://docs.apify.com/academy`,
    inputSchema: zodToJsonSchema(fetchApifyDocsToolArgsSchema) as ToolInputSchema,
    ajvValidate: ajv.compile(zodToJsonSchema(fetchApifyDocsToolArgsSchema)),
    annotations: {
        title: 'Fetch Apify docs',
        readOnlyHint: true,
        openWorldHint: false,
    },
    call: async (toolArgs: InternalToolArgs) => {
        const { args } = toolArgs;

        const parsed = fetchApifyDocsToolArgsSchema.parse(args);
        const url = parsed.url.trim();
        const urlWithoutFragment = url.split('#')[0];

        // Only allow URLs starting with https://docs.apify.com
        if (!url.startsWith('https://docs.apify.com')) {
            return buildMCPResponse([`Invalid URL: "${url}".
Only URLs starting with "https://docs.apify.com" are allowed.
Please provide a valid Apify documentation URL. You can find documentation URLs using the ${HelperTools.DOCS_SEARCH} tool.`], true);
        }

        // Cache URL without fragment to avoid fetching the same page multiple times
        let markdown = fetchApifyDocsCache.get(urlWithoutFragment);
        // If the content is not cached, fetch it from the URL
        if (!markdown) {
            try {
                const response = await fetch(url);
                if (!response.ok) {
                    const error = Object.assign(new Error(`HTTP ${response.status} ${response.statusText}`), {
                        statusCode: response.status,
                    });
                    logHttpError(error, 'Failed to fetch the documentation page', { url, statusText: response.statusText });
                    return buildMCPResponse([`Failed to fetch the documentation page at "${url}".
HTTP Status: ${response.status} ${response.statusText}.
Please verify the URL is correct and accessible. You can search for available documentation pages using the ${HelperTools.DOCS_SEARCH} tool.`], true);
                }
                const html = await response.text();
                markdown = htmlToMarkdown(html);
                // Cache the processed Markdown content
                // Use the URL without fragment as the key to avoid caching same page with different fragments
                fetchApifyDocsCache.set(urlWithoutFragment, markdown);
            } catch (error) {
                logHttpError(error, 'Failed to fetch the documentation page', { url });
                return buildMCPResponse([`Failed to fetch the documentation page at "${url}".
Error: ${error instanceof Error ? error.message : String(error)}.
Please verify the URL is correct and accessible. You can search for available documentation pages using the ${HelperTools.DOCS_SEARCH} tool.`], true);
            }
        }

        return buildMCPResponse([`Fetched content from ${url}:\n\n${markdown}`]);
    },
} as const;
